package com.fary.web.context.request.async;

import com.fary.beans.factory.BeanFactory;
import com.fary.beans.factory.BeanFactoryAware;
import com.fary.core.task.AsyncTaskExecutor;
import com.fary.util.Assert;
import com.fary.web.context.request.NativeWebRequest;

import java.util.concurrent.Callable;

public class WebAsyncTask<V> implements BeanFactoryAware {

    // 线程
    private final Callable<V> callable;

    // 超时时间
    private Long timeout;

    // 线程池
    private AsyncTaskExecutor executor;

    // 配置的线程池beanName
    private String executorName;

    // BeanFactory容器
    private BeanFactory beanFactory;

    // 超时回调
    private Callable<V> timeoutCallback;

    // 错误回调
    private Callable<V> errorCallback;

    // 完成回调
    private Runnable completionCallback;

    public WebAsyncTask(Callable<V> callable) {
        Assert.notNull(callable, "Callable must not be null");
        this.callable = callable;
    }

    public WebAsyncTask(long timeout, Callable<V> callable) {
        this(callable);
        this.timeout = timeout;
    }

    public WebAsyncTask(Long timeout, String executorName, Callable<V> callable) {
        this(callable);
        Assert.notNull(executorName, "Executor name must not be null");
        this.executorName = executorName;
        this.timeout = timeout;
    }

    public WebAsyncTask(Long timeout, AsyncTaskExecutor executor, Callable<V> callable) {
        this(callable);
        Assert.notNull(executor, "Executor must not be null");
        this.executor = executor;
        this.timeout = timeout;
    }

    public Callable<?> getCallable() {
        return this.callable;
    }

    public Long getTimeout() {
        return this.timeout;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }

    /**
     * Return the AsyncTaskExecutor to use for concurrent handling,
     * or {@code null} if none specified.
     */
    public AsyncTaskExecutor getExecutor() {
        if (this.executor != null) {
            return this.executor;
        } else if (this.executorName != null) {
            Assert.state(this.beanFactory != null, "BeanFactory is required to look up an executor bean by name");
            return this.beanFactory.getBean(this.executorName, AsyncTaskExecutor.class);
        } else {
            return null;
        }
    }

    public void onTimeout(Callable<V> callback) {
        this.timeoutCallback = callback;
    }

    public void onError(Callable<V> callback) {
        this.errorCallback = callback;
    }

    public void onCompletion(Runnable callback) {
        this.completionCallback = callback;
    }

    // 线程执行拦截器，针对超时、错误、完成时回调处理
    CallableProcessingInterceptor getInterceptor() {
        return new CallableProcessingInterceptor() {
            @Override
            public <T> Object handleTimeout(NativeWebRequest request, Callable<T> task) throws Exception {
                return (timeoutCallback != null ? timeoutCallback.call() : CallableProcessingInterceptor.RESULT_NONE);
            }

            @Override
            public <T> Object handleError(NativeWebRequest request, Callable<T> task, Throwable t) throws Exception {
                return (errorCallback != null ? errorCallback.call() : CallableProcessingInterceptor.RESULT_NONE);
            }

            @Override
            public <T> void afterCompletion(NativeWebRequest request, Callable<T> task) throws Exception {
                if (completionCallback != null) {
                    completionCallback.run();
                }
            }
        };
    }

}